package com.ittao.taopicture.infrastructure.utils;

import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.security.MessageDigest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 图片抓取工具类 - 优化版
 * 封装必应图片抓取的核心逻辑，增强多样性和质量控制
 * 支持时间感知的多样化抓取，确保每天抓取不同内容
 *
 * @author ittao
 * @date 2025/08/07
 */
@SuppressWarnings({"UnnecessaryUnicodeEscape", "BusyWait", "LoggingPlaceholderCountMatchesArgumentCount"})
@Slf4j
public class BingImageCrawlerUtils {

    // 内容相似度检测缓存
    private static final Map<String, String> CONTENT_HASH_CACHE = new ConcurrentHashMap<>();

    // 质量评分缓存
    private static final Map<String, Double> QUALITY_SCORE_CACHE = new ConcurrentHashMap<>();

    // 每日搜索策略缓存 - 确保同一天内策略一致，不同天策略不同
    private static final Map<String, List<SearchStrategy>> DAILY_STRATEGY_CACHE = new ConcurrentHashMap<>();

    /**
     * 必应图片抓取核心方法
     * 从指定页面抓取图片元素并返回处理后的URL列表
     *
     * @param searchText    搜索关键词
     * @param currentOffset 当前偏移量
     * @return 图片URL列表
     */
    public static List<String> crawlSinglePage(String searchText, int currentOffset) {
        List<String> imageUrls = new ArrayList<>();

        try {
            // 抓取当前页面
            String fetchUrl = String.format("https://cn.bing.com/images/async?q=%s&first=%d&mmasync=1",
                    searchText, currentOffset);

            Document document = Jsoup.connect(fetchUrl)
                    .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                    .timeout(10000)
                    .get();

            // 解析内容
            Element div = document.getElementsByClass("dgControl").first();
            if (div == null) {
                log.warn("未找到图片容器，偏移量: {}", currentOffset);
                return imageUrls;
            }

            Elements imgElementList = div.select("img.mimg");
            if (imgElementList.isEmpty()) {
                log.warn("没有找到图片元素，可能已到达搜索结果末尾");
                return imageUrls;
            }

            // 处理当前页面的图片
            for (Element imgElement : imgElementList) {
                String originalFileUrl = imgElement.attr("src");
                if (StrUtil.isBlank(originalFileUrl)) {
                    continue;
                }

                // 尝试获取更高质量的图片URL
                String optimizedUrl = getHighQualityImageUrl(imgElement, originalFileUrl);
                String fileUrl = StrUtil.isNotBlank(optimizedUrl) ? optimizedUrl : originalFileUrl;

                imageUrls.add(fileUrl);
            }

        } catch (Exception e) {
            log.error("抓取页面失败，偏移量: {}, 错误: {}", currentOffset, e.getMessage());
        }

        return imageUrls;
    }

    /**
     * 尝试获取更高质量的图片URL
     */
    private static String getHighQualityImageUrl(Element imgElement, String originalUrl) {
        try {
            // 针对必应图片的处理 - 通过修改URL参数获取更大尺寸的图片
            if (originalUrl.contains("bing.net") && originalUrl.contains("/th/id/") && originalUrl.contains("?")) {
                String enlargedUrl = getBingEnlargedUrl(originalUrl);
                if (StrUtil.isNotBlank(enlargedUrl) && !enlargedUrl.equals(originalUrl)) {
                    return enlargedUrl;
                }
            }

            // 通用策略：尝试从data-src属性获取
            String dataSrc = imgElement.attr("data-src");
            if (StrUtil.isNotBlank(dataSrc)) {
                return dataSrc;
            }

            return originalUrl;

        } catch (Exception e) {
            log.error("获取高质量图片URL失败: {}", e.getMessage());
            return originalUrl;
        }
    }

    /**
     * 通过修改Bing URL参数获取更大尺寸的图片
     */
    private static String getBingEnlargedUrl(String originalUrl) {
        try {
            String baseUrl = originalUrl.substring(0, originalUrl.indexOf("?"));

            // 默认512x512，进行智能优化
            int targetWidth = 512;
            int targetHeight = 512;

            // 尝试解析原始尺寸进行智能缩放
            try {
                String queryString = originalUrl.substring(originalUrl.indexOf("?") + 1);
                Map<String, String> params = new HashMap<>();
                String[] pairs = queryString.split("&");
                for (String pair : pairs) {
                    String[] keyValue = pair.split("=", 2);
                    if (keyValue.length == 2) {
                        params.put(keyValue[0], keyValue[1]);
                    }
                }

                if (params.containsKey("w") && params.containsKey("h")) {
                    int originalWidth = Integer.parseInt(params.get("w"));
                    int originalHeight = Integer.parseInt(params.get("h"));

                    // 智能计算目标尺寸
                    int[] optimalSize = calculateOptimalSize(originalWidth, originalHeight);
                    targetWidth = optimalSize[0];
                    targetHeight = optimalSize[1];
                }
            } catch (Exception e) {
                log.debug("无法解析原始尺寸，使用默认512x512");
            }

            // 构建优化URL
            return baseUrl + "?w=" + targetWidth + "&h=" + targetHeight +
                    "&c=1&rs=1&o=6&qlt=95&fmt=jpg&r=" + (System.currentTimeMillis() % 10000);

        } catch (Exception e) {
            log.error("处理Bing URL失败: {}", e.getMessage());
            // 兜底方案
            try {
                String baseUrl = originalUrl.substring(0, originalUrl.indexOf("?"));
                return baseUrl + "?w=512&h=512&c=1&rs=1&o=6&qlt=95&fmt=jpg";
            } catch (Exception e2) {
                return originalUrl;
            }
        }
    }

    /**
     * 计算最优图片尺寸 - 修复版
     * 确保宽高最小都是512，然后进行等比例缩放
     */
    private static int[] calculateOptimalSize(int originalWidth, int originalHeight) {
        // 尺寸配置
        final int MIN_SIZE = 512;            // 最小尺寸要求（宽高都要≥512）
        final int MAX_SIZE = 1080;           // 最大尺寸限制
        final double MAX_SCALE_UP = 3.0;     // 最大放大倍数

        // 保护：避免无效输入
        if (originalWidth <= 0 || originalHeight <= 0) {
            log.warn("无效的原始尺寸: {}x{}, 使用默认512x512", originalWidth, originalHeight);
            return new int[]{512, 512};
        }

        double originalRatio = (double) originalWidth / originalHeight;
        int targetWidth = originalWidth;
        int targetHeight = originalHeight;

        // 策略1: 如果原始尺寸已经满足最小要求且不超过最大限制
        if (originalWidth >= MIN_SIZE && originalHeight >= MIN_SIZE &&
                originalWidth <= MAX_SIZE && originalHeight <= MAX_SIZE) {
            log.debug("尺寸已经合适: {}x{} -> 保持原样", originalWidth, originalHeight);
            return new int[]{originalWidth, originalHeight};
        }

        // 策略2: 如果有任一边小于512，需要等比放大确保两边都≥512
        if (originalWidth < MIN_SIZE || originalHeight < MIN_SIZE) {
            // 计算需要的放大倍数：取两边中需要更大放大倍数的那个
            double scaleToReachMin = Math.max(
                    (double) MIN_SIZE / originalWidth,
                    (double) MIN_SIZE / originalHeight
            );

            // 限制最大放大倍数，避免图片过度模糊
            scaleToReachMin = Math.min(scaleToReachMin, MAX_SCALE_UP);

            targetWidth = (int) (originalWidth * scaleToReachMin);
            targetHeight = (int) (originalHeight * scaleToReachMin);

            log.debug("小尺寸等比放大: {}x{} -> {}x{} (放大倍数: {:.2f})",
                    originalWidth, originalHeight, targetWidth, targetHeight, scaleToReachMin);
        }

        // 策略3: 如果放大后或原始尺寸超过最大限制，需要等比缩小
        if (targetWidth > MAX_SIZE || targetHeight > MAX_SIZE) {
            double scaleToFitMax = Math.min(
                    (double) MAX_SIZE / targetWidth,
                    (double) MAX_SIZE / targetHeight
            );

            targetWidth = (int) (targetWidth * scaleToFitMax);
            targetHeight = (int) (targetHeight * scaleToFitMax);

            log.debug("大尺寸等比缩小: 缩小倍数 {:.2f} -> {}x{}",
                    scaleToFitMax, targetWidth, targetHeight);
        }

        // 最终检查：确保最小尺寸要求（如果缩小后仍然不满足，优先保证最小尺寸）
        if (targetWidth < MIN_SIZE || targetHeight < MIN_SIZE) {
            log.warn("缩放后仍不满足最小尺寸要求，强制调整到最小尺寸");
            double finalScale = Math.max(
                    (double) MIN_SIZE / targetWidth,
                    (double) MIN_SIZE / targetHeight
            );
            targetWidth = (int) (targetWidth * finalScale);
            targetHeight = (int) (targetHeight * finalScale);
        }

        // 验证最终比例是否合理（容差5%）
        double finalRatio = (double) targetWidth / targetHeight;
        if (Math.abs(finalRatio - originalRatio) / originalRatio > 0.05) {
            log.warn("尺寸计算存在比例偏差: 原始{}x{}(比例{:.3f}) -> 目标{}x{}(比例{:.3f})",
                    originalWidth, originalHeight, originalRatio,
                    targetWidth, targetHeight, finalRatio);
        } else {
            log.debug("尺寸优化完成: {}x{} -> {}x{} (比例保持: {:.3f})",
                    originalWidth, originalHeight, targetWidth, targetHeight, finalRatio);
        }

        return new int[]{targetWidth, targetHeight};
    }

    /**
     * 优化的批量抓取方法 - 确保百分百返回指定数量的图片
     * 采用多级策略和兜底机制，绝对保证数量要求
     *
     * @param searchText   搜索关键词
     * @param targetCount  目标抓取数量
     * @param existingUrls 已存在的URL集合
     * @return 去重后的图片URL列表，数量等于targetCount
     */
    public static List<String> crawlDiverseImages(String searchText, int targetCount, Set<String> existingUrls) {
        List<String> finalResults = new ArrayList<>();
        Set<String> urlHashes = new HashSet<>(); // URL去重
        Set<String> contentHashes = new HashSet<>(); // 内容相似度去重
        Map<String, Integer> domainCounter = new HashMap<>(); // 域名分散统计

        // 清理缓存
        cleanupCache();

        log.info("开始抓取，目标{}张图片，采用多级策略确保数量", targetCount);

        // 第一级：高质量多样化抓取
        List<String> highQualityResults = performHighQualitySearch(searchText, targetCount, existingUrls,
                urlHashes, contentHashes, domainCounter);
        finalResults.addAll(highQualityResults);

        // 如果数量足够，直接返回
        if (finalResults.size() >= targetCount) {
            log.info("高质量抓取完成，获得{}张图片", finalResults.size());
            return finalResults.subList(0, targetCount);
        }

        log.info("高质量抓取获得{}张，需要补充{}张", finalResults.size(), targetCount - finalResults.size());

        // 第二级：放宽条件抓取
        int remainingCount = targetCount - finalResults.size();
        List<String> mediumQualityResults = performMediumQualitySearch(searchText, remainingCount,
                existingUrls, urlHashes, contentHashes, domainCounter);
        finalResults.addAll(mediumQualityResults);

        // 如果数量足够，直接返回
        if (finalResults.size() >= targetCount) {
            log.info("中等质量抓取完成，总计获得{}张图片", finalResults.size());
            return finalResults.subList(0, targetCount);
        }

        log.info("中等质量抓取后总计{}张，还需补充{}张", finalResults.size(), targetCount - finalResults.size());

        // 第三级：兜底抓取 - 确保数量
        remainingCount = targetCount - finalResults.size();
        List<String> fallbackResults = performFallbackSearch(searchText, remainingCount,
                existingUrls, urlHashes);
        finalResults.addAll(fallbackResults);

        // 最终保证：如果还不够，进行基础抓取直到满足数量
        if (finalResults.size() < targetCount) {
            log.warn("前三级抓取仍不足，启动基础抓取兜底机制");
            remainingCount = targetCount - finalResults.size();
            List<String> basicResults = performBasicSearch(searchText, remainingCount, urlHashes);
            finalResults.addAll(basicResults);
        }

        // 确保返回精确数量
        int actualSize = Math.min(finalResults.size(), targetCount);
        List<String> result = finalResults.subList(0, actualSize);

        log.info("抓取完成！要求{}张，实际返回{}张", targetCount, result.size());
        return result;
    }

    /**
     * 第一级：高质量多样化抓取
     */
    private static List<String> performHighQualitySearch(String searchText, int targetCount,
                                                         Set<String> existingUrls, Set<String> urlHashes,
                                                         Set<String> contentHashes, Map<String, Integer> domainCounter) {
        List<String> results = new ArrayList<>();

        // 获取今日专属的搜索策略
        List<SearchStrategy> strategies = getDailySearchStrategies(searchText);

        // 智能延迟管理器
        SmartDelayManager delayManager = new SmartDelayManager();

        for (SearchStrategy strategy : strategies) {
            if (results.size() >= targetCount) {
                break;
            }

            int[] startOffsets = generateDailyRandomOffsets(strategy.getOffsetRange(), searchText);

            for (int startOffset : startOffsets) {
                if (results.size() >= targetCount) {
                    break;
                }

                for (int page = 0; page < strategy.getMaxPages() && results.size() < targetCount; page++) {
                    int offset = startOffset + page * 35;

                    List<String> pageUrls = crawlSinglePage(strategy.getQuery(), offset);
                    if (pageUrls.isEmpty()) {
                        break;
                    }

                    // 高质量智能筛选
                    List<String> qualifiedUrls = intelligentFilterHighQuality(pageUrls, existingUrls,
                            urlHashes, contentHashes, domainCounter);

                    results.addAll(qualifiedUrls);

                    // 更新统计信息
                    for (String url : qualifiedUrls) {
                        urlHashes.add(getUrlHash(url));
                        String domain = extractDomain(url);
                        domainCounter.put(domain, domainCounter.getOrDefault(domain, 0) + 1);
                    }

                    // 智能延迟：根据抓取成功率动态调整
                    delayManager.smartDelay(qualifiedUrls.size(), pageUrls.size());
                }
            }
        }

        return results;
    }

    /**
     * 第二级：放宽条件抓取
     */
    private static List<String> performMediumQualitySearch(String searchText, int targetCount,
                                                           Set<String> existingUrls, Set<String> urlHashes,
                                                           Set<String> contentHashes, Map<String, Integer> domainCounter) {
        List<String> results = new ArrayList<>();

        // 使用更多搜索词变体
        String[] searchVariants = {
                searchText,
                searchText + " 图片",
                searchText + " photo",
                searchText + " image",
                "精美 " + searchText,
                searchText + " 壁纸"
        };

        SmartDelayManager delayManager = new SmartDelayManager();

        for (String variant : searchVariants) {
            if (results.size() >= targetCount) {
                break;
            }

            // 扩大搜索范围，但使用并行处理
            List<Integer> offsets = new ArrayList<>();
            for (int offset = 0; offset < 500 && results.size() < targetCount; offset += 35) {
                offsets.add(offset);
            }

            // 批量处理，减少总延迟时间
            for (int i = 0; i < offsets.size() && results.size() < targetCount; i += 3) {
                List<Integer> batch = offsets.subList(i, Math.min(i + 3, offsets.size()));

                for (Integer offset : batch) {
                    if (results.size() >= targetCount) {
                        break;
                    }

                    List<String> pageUrls = crawlSinglePage(variant, offset);
                    if (pageUrls.isEmpty()) {
                        continue;
                    }

                    // 中等质量过滤（放宽标准）
                    List<String> qualifiedUrls = intelligentFilterMediumQuality(pageUrls, existingUrls,
                            urlHashes, contentHashes, domainCounter);

                    results.addAll(qualifiedUrls);

                    // 更新统计
                    for (String url : qualifiedUrls) {
                        urlHashes.add(getUrlHash(url));
                        String domain = extractDomain(url);
                        domainCounter.put(domain, domainCounter.getOrDefault(domain, 0) + 1);
                    }
                }

                // 批量处理后只延迟一次
                if (i + 3 < offsets.size()) {
                    delayManager.batchDelay();
                }
            }
        }

        return results;
    }

    /**
     * 第三级：兜底抓取
     */
    private static List<String> performFallbackSearch(String searchText, int targetCount,
                                                      Set<String> existingUrls, Set<String> urlHashes) {
        List<String> results = new ArrayList<>();

        // 非常宽松的搜索词
        String[] fallbackTerms = {
                searchText + " picture",
                searchText + " 照片",
                searchText + " 素材",
                "相关 " + searchText,
                searchText.replaceAll("\\s+", ""), // 去空格
        };

        SmartDelayManager delayManager = new SmartDelayManager(true); // 兜底模式，延迟更短

        for (String term : fallbackTerms) {
            if (results.size() >= targetCount) {
                break;
            }

            // 快速扫描模式：每5页批量处理
            for (int batchStart = 0; batchStart < 1000 && results.size() < targetCount; batchStart += 175) { // 5页一批
                int successCount = 0;

                for (int offset = batchStart; offset < batchStart + 175 && results.size() < targetCount; offset += 35) {
                    List<String> pageUrls = crawlSinglePage(term, offset);
                    if (pageUrls.isEmpty()) {
                        continue;
                    }

                    successCount++;

                    // 最宽松的过滤（只去重和检查基本有效性）
                    for (String url : pageUrls) {
                        if (results.size() >= targetCount) {
                            break;
                        }

                        if (isValidUrl(url) && !existingUrls.contains(url) &&
                                !urlHashes.contains(getUrlHash(url))) {
                            results.add(url);
                            urlHashes.add(getUrlHash(url));
                        }
                    }
                }

                // 根据成功率决定是否延迟
                if (successCount > 0 && batchStart + 175 < 1000) {
                    delayManager.adaptiveDelay(successCount);
                }
            }
        }

        return results;
    }

    /**
     * 第四级：基础抓取（终极兜底）- 最快速度
     */
    private static List<String> performBasicSearch(String searchText, int targetCount, Set<String> urlHashes) {
        List<String> results = new ArrayList<>();

        // 使用最基本的搜索词
        String[] basicTerms = {searchText, "图片", "photo", "image", "picture"};

        for (String term : basicTerms) {
            if (results.size() >= targetCount) {
                break;
            }

            // 极速抓取模式：10页一批，最小延迟
            for (int batchStart = 0; batchStart < 2000 && results.size() < targetCount; batchStart += 350) { // 10页一批

                for (int offset = batchStart; offset < batchStart + 350 && results.size() < targetCount; offset += 35) {
                    List<String> pageUrls = crawlSinglePage(term, offset);

                    // 最基本的过滤：只要是有效URL就行
                    for (String url : pageUrls) {
                        if (results.size() >= targetCount) {
                            break;
                        }

                        if (isValidUrl(url) && !urlHashes.contains(getUrlHash(url))) {
                            results.add(url);
                            urlHashes.add(getUrlHash(url));
                        }
                    }
                }

                // 极简延迟：只在必要时暂停
                if (results.size() < targetCount && batchStart + 350 < 2000) {
                    try {
                        Thread.sleep(100); // 最小延迟
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        return results;
    }

    /**
     * 高质量智能过滤器
     */
    private static List<String> intelligentFilterHighQuality(List<String> urls, Set<String> existingUrls,
                                                             Set<String> urlHashes, Set<String> contentHashes,
                                                             Map<String, Integer> domainCounter) {
        List<String> qualified = new ArrayList<>();

        for (String url : urls) {
            if (qualified.size() >= 15) {
                break; // 每页最多15张
            }

            // 基础去重
            if (existingUrls.contains(url) || urlHashes.contains(getUrlHash(url))) {
                continue;
            }

            // 质量评分
            double qualityScore = QUALITY_SCORE_CACHE.computeIfAbsent(url, BingImageCrawlerUtils::calculateQualityScore);
            if (qualityScore < 0.6) {
                continue;
            }

            // 内容相似度
            String contentHash = generateContentHash(url);
            if (contentHashes.contains(contentHash)) {
                continue;
            }

            // 域名分散
            String domain = extractDomain(url);
            if (domainCounter.getOrDefault(domain, 0) >= 5) {
                continue;
            }

            // 尺寸检查
            if (!isReasonableSize(url)) {
                continue;
            }

            qualified.add(url);
            contentHashes.add(contentHash);
        }

        return qualified;
    }

    /**
     * 中等质量智能过滤器（放宽标准）
     */
    private static List<String> intelligentFilterMediumQuality(List<String> urls, Set<String> existingUrls,
                                                               Set<String> urlHashes, Set<String> contentHashes,
                                                               Map<String, Integer> domainCounter) {
        List<String> qualified = new ArrayList<>();

        for (String url : urls) {
            if (qualified.size() >= 20) {
                break; // 每页最多20张
            }

            // 基础去重
            if (existingUrls.contains(url) || urlHashes.contains(getUrlHash(url))) {
                continue;
            }

            // 降低质量门槛
            double qualityScore = QUALITY_SCORE_CACHE.computeIfAbsent(url, BingImageCrawlerUtils::calculateQualityScore);
            if (qualityScore < 0.3) {
                continue;
            }

            // 放宽域名限制
            String domain = extractDomain(url);
            if (domainCounter.getOrDefault(domain, 0) >= 15) {
                continue;
            }

            // 基本尺寸检查
            if (!isValidUrl(url)) {
                continue;
            }

            qualified.add(url);
        }

        return qualified;
    }

    /**
     * 检查URL是否有效
     */
    private static boolean isValidUrl(String url) {
        if (StrUtil.isBlank(url)) {
            return false;
        }

        // 基本格式检查
        if (!url.startsWith("http")) {
            return false;
        }

        // 排除明显无效的URL
        String lowerUrl = url.toLowerCase();
        return !lowerUrl.contains("icon") && !lowerUrl.contains("favicon") &&
                !lowerUrl.contains("logo") && !lowerUrl.contains("avatar");
    }

    /**
     * 获取今日专属的搜索策略 - 基于日期生成不同的搜索策略组合
     * 确保同一关键词在不同日期会产生不同的搜索策略
     */
    private static List<SearchStrategy> getDailySearchStrategies(String originalSearch) {
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String cacheKey = today + ":" + originalSearch;

        // 检查今日是否已生成策略
        List<SearchStrategy> cachedStrategies = DAILY_STRATEGY_CACHE.get(cacheKey);
        if (cachedStrategies != null) {
            log.debug("使用今日缓存的搜索策略，共 {} 种", cachedStrategies.size());
            return cachedStrategies;
        }

        // 生成今日专属的搜索策略
        List<SearchStrategy> todayStrategies = generateTimeBasedSearchStrategies(originalSearch, today);

        // 缓存今日策略（避免同一天内重复计算）
        DAILY_STRATEGY_CACHE.put(cacheKey, todayStrategies);

        // 清理过期缓存（保留最近3天）
        cleanupDailyStrategyCache();

        log.info("生成今日专属搜索策略，共 {} 种", todayStrategies.size());
        return todayStrategies;
    }

    /**
     * 基于时间生成搜索策略 - 让每天的搜索都不一样
     */
    private static List<SearchStrategy> generateTimeBasedSearchStrategies(String originalSearch, String dateStr) {
        List<SearchStrategy> strategies = new ArrayList<>();

        // 使用日期作为随机种子，确保同一天结果一致，不同天结果不同
        Random dayRandom = new Random(dateStr.hashCode());

        // 1. 原始搜索（永远保留）
        strategies.add(new SearchStrategy("原始搜索", originalSearch, 200, 3, 800));

        // 2. 高质量变体 - 每天随机选择3-4个
        String[] qualityModifiers = {"4K", "高清", "精美", "专业摄影", "艺术作品", "wallpaper",
                "超清", "精品", "大师", "获奖", "经典", "唯美"};
        List<String> selectedQuality = getRandomSelection(qualityModifiers, 3 + dayRandom.nextInt(2), dayRandom);
        for (String modifier : selectedQuality) {
            strategies.add(new SearchStrategy("高质量-" + modifier,
                    modifier + " " + originalSearch, 300, 2, 1000));
        }

        // 3. 风格变体 - 每天随机选择2-3个
        String[] styleVariants = {"插画", "摄影", "设计", "手绘", "数字艺术", "概念图", "实拍", "CG"};
        List<String> selectedStyles = getRandomSelection(styleVariants, 2 + dayRandom.nextInt(2), dayRandom);
        for (String style : selectedStyles) {
            strategies.add(new SearchStrategy("风格-" + style,
                    originalSearch + " " + style, 400, 2, 1200));
        }

        // 4. 时间相关变体 - 根据日期动态生成
        String[] timeModifiers = getTimeBasedModifiers(dateStr);
        for (String timeModifier : timeModifiers) {
            strategies.add(new SearchStrategy("时间感知-" + timeModifier,
                    timeModifier + " " + originalSearch, 350, 2, 900));
        }

        // 5. 英文搜索（如果原始是中文）
        if (containsChinese(originalSearch)) {
            String englishKeyword = translateToEnglishKeywords(originalSearch);
            // 每天添加不同的英文修饰词
            String[] englishModifiers = {"modern", "creative", "professional", "artistic", "premium", "trending"};
            String selectedModifier = englishModifiers[dayRandom.nextInt(englishModifiers.length)];
            strategies.add(new SearchStrategy("英文搜索",
                    selectedModifier + " " + englishKeyword, 500, 3, 1000));
        }

        // 6. 颜色主题变体 - 每天随机选择1-2个
        String[] colorThemes = {"彩色", "黑白", "蓝色主题", "温暖色调", "冷色调", "高对比", "柔和色彩", "鲜艳"};
        List<String> selectedColors = getRandomSelection(colorThemes, 1 + dayRandom.nextInt(2), dayRandom);
        for (String color : selectedColors) {
            strategies.add(new SearchStrategy("色彩-" + color,
                    color + " " + originalSearch, 600, 2, 1500));
        }

        // 7. 随机组合变体 - 每天生成1-2个创意组合
        strategies.addAll(generateCreativeCombinations(originalSearch, dayRandom));

        // 打乱策略顺序，增加随机性
        Collections.shuffle(strategies, dayRandom);

        return strategies;
    }

    /**
     * 基于日期生成时间相关的修饰词
     */
    private static String[] getTimeBasedModifiers(String dateStr) {
        List<String> timeModifiers = new ArrayList<>();

        // 根据日期的不同特征生成不同修饰词
        int dayOfMonth = Integer.parseInt(dateStr.substring(8, 10));
        int month = Integer.parseInt(dateStr.substring(5, 7));

        // 基于日期数字的修饰词
        if (dayOfMonth % 7 == 0) {
            timeModifiers.add("最新");
        } else if (dayOfMonth % 7 == 1) {
            timeModifiers.add("热门");
        } else if (dayOfMonth % 7 == 2) {
            timeModifiers.add("推荐");
        } else if (dayOfMonth % 7 == 3) {
            timeModifiers.add("精选");
        } else if (dayOfMonth % 7 == 4) {
            timeModifiers.add("优质");
        } else if (dayOfMonth % 7 == 5) {
            timeModifiers.add("独特");
        } else {
            timeModifiers.add("创意");
        }

        // 基于月份的季节性修饰词
        if (month >= 3 && month <= 5) {
            timeModifiers.add("春季");
        } else if (month >= 6 && month <= 8) {
            timeModifiers.add("夏季");
        } else if (month >= 9 && month <= 11) {
            timeModifiers.add("秋季");
        } else {
            timeModifiers.add("冬季");
        }

        return timeModifiers.toArray(new String[0]);
    }

    /**
     * 从数组中随机选择指定数量的元素
     */
    private static List<String> getRandomSelection(String[] array, int count, Random random) {
        List<String> list = Arrays.asList(array);
        Collections.shuffle(list, random);
        return list.subList(0, Math.min(count, list.size()));
    }

    /**
     * 生成创意组合搜索词
     */
    private static List<SearchStrategy> generateCreativeCombinations(String originalSearch, Random dayRandom) {
        List<SearchStrategy> combinations = new ArrayList<>();

        String[] prefixes = {"现代", "复古", "简约", "华丽", "神秘", "明亮"};
        String[] suffixes = {"风格", "主题", "系列", "作品", "设计", "图案"};

        // 生成1-2个创意组合
        int combinationCount = 1 + dayRandom.nextInt(2);
        for (int i = 0; i < combinationCount; i++) {
            String prefix = prefixes[dayRandom.nextInt(prefixes.length)];
            String suffix = suffixes[dayRandom.nextInt(suffixes.length)];
            String creativeTerm = prefix + originalSearch + suffix;

            combinations.add(new SearchStrategy("创意组合-" + prefix + suffix,
                    creativeTerm, 450, 2, 1100));
        }

        return combinations;
    }

    /**
     * 基于日期和关键词生成今日专属的随机偏移量
     * 确保同一天同一关键词的偏移量相同，但不同天不同
     */
    private static int[] generateDailyRandomOffsets(int range, String searchText) {
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 使用日期和搜索词生成今日专属的随机种子
        long seed = (today + searchText).hashCode();
        Random dayRandom = new Random(seed);

        int[] offsets = new int[4]; // 增加到4个起点
        for (int i = 0; i < offsets.length; i++) {
            offsets[i] = dayRandom.nextInt(range) + i * 100; // 确保起点分散
        }

        log.debug("今日专属随机偏移量: {}", Arrays.toString(offsets));
        return offsets;
    }

    /**
     * 清理缓存
     */
    private static void cleanupCache() {
        if (CONTENT_HASH_CACHE.size() > 1000) {
            CONTENT_HASH_CACHE.clear();
        }
        if (QUALITY_SCORE_CACHE.size() > 1000) {
            QUALITY_SCORE_CACHE.clear();
        }
    }

    /**
     * 清理过期的每日策略缓存
     */
    private static void cleanupDailyStrategyCache() {
        if (DAILY_STRATEGY_CACHE.size() > 10) { // 保留最近10天
            String threeDaysAgo = LocalDate.now().minusDays(3).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            DAILY_STRATEGY_CACHE.entrySet().removeIf(entry -> entry.getKey().compareTo(threeDaysAgo) < 0);
        }
    }

    /**
     * 计算图片质量评分
     */
    private static double calculateQualityScore(String url) {
        double score = 0.5; // 基础分

        try {
            // 尺寸评分
            String widthStr = extractUrlParameter(url, "w");
            String heightStr = extractUrlParameter(url, "h");
            if (widthStr != null && heightStr != null) {
                int width = Integer.parseInt(widthStr);
                int height = Integer.parseInt(heightStr);

                // 高分辨率加分
                if (width >= 1920 && height >= 1080) {
                    score += 0.3;
                } else if (width >= 1024 && height >= 768) {
                    score += 0.2;
                } else if (width >= 512 && height >= 512) {
                    score += 0.1;
                }

                // 合理宽高比加分
                double ratio = Math.max(width, height) / (double) Math.min(width, height);
                if (ratio <= 2.0) {
                    score += 0.1;
                }
            }

            // URL特征评分
            String lowerUrl = url.toLowerCase();
            if (lowerUrl.contains("qlt=") && extractUrlParameter(url, "qlt") != null) {
                try {
                    int quality = Integer.parseInt(Objects.requireNonNull(extractUrlParameter(url, "qlt")));
                    if (quality >= 90) {
                        score += 0.2;
                    } else if (quality >= 80) {
                        score += 0.1;
                    }
                } catch (Exception ignored) {
                }
            }

            // 来源质量评分
            if (lowerUrl.contains("bing.net")) {
                score += 0.1;
            }
            if (lowerUrl.contains("fmt=jpg") || lowerUrl.contains("fmt=jpeg")) {
                score += 0.05;
            }

            // 负面因素扣分
            if (lowerUrl.contains("thumbnail")) {
                score -= 0.2;
            }
            if (lowerUrl.contains("small")) {
                score -= 0.15;
            }
            if (lowerUrl.contains("icon")) {
                score -= 0.3;
            }

        } catch (Exception e) {
            log.debug("质量评分计算异常: {}", e.getMessage());
        }

        return Math.max(0.0, Math.min(1.0, score));
    }

    /**
     * 生成内容相似度hash
     */
    private static String generateContentHash(String url) {
        return CONTENT_HASH_CACHE.computeIfAbsent(url, u -> {
            try {
                // 提取关键特征进行hash
                StringBuilder features = new StringBuilder();

                // 尺寸特征（归一化）
                String widthStr = extractUrlParameter(u, "w");
                String heightStr = extractUrlParameter(u, "h");
                if (widthStr != null && heightStr != null) {
                    int width = Integer.parseInt(widthStr);
                    int height = Integer.parseInt(heightStr);
                    // 按比例区间分类
                    double ratio = (double) width / height;
                    String ratioCategory = getRatioCategory(ratio);
                    features.append(ratioCategory).append(":");
                }

                // 提取文件ID（如果存在）
                String fileId = extractFileIdentifier(u);
                if (fileId != null) {
                    features.append(fileId);
                }

                // 生成MD5 hash
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] hash = md.digest(features.toString().getBytes());
                StringBuilder hexString = new StringBuilder();
                for (byte b : hash) {
                    String hex = Integer.toHexString(0xff & b);
                    if (hex.length() == 1) {
                        hexString.append('0');
                    }
                    hexString.append(hex);
                }
                return hexString.substring(0, 8); // 取前8位

            } catch (Exception e) {
                return String.valueOf(u.hashCode());
            }
        });
    }

    /**
     * 生成URL的简化hash，用于去重
     */
    private static String getUrlHash(String url) {
        // 移除参数后生成hash，避免参数不同但内容相同的重复
        String cleanUrl = url;
        int questionIndex = cleanUrl.indexOf('?');
        if (questionIndex > 0) {
            cleanUrl = cleanUrl.substring(0, questionIndex);
        }
        return String.valueOf(cleanUrl.hashCode());
    }

    /**
     * 从URL中提取指定参数值
     */
    private static String extractUrlParameter(String url, String paramName) {
        int paramIndex = url.indexOf(paramName + "=");
        if (paramIndex == -1) {
            return null;
        }

        int valueStart = paramIndex + paramName.length() + 1;
        int valueEnd = url.indexOf("&", valueStart);
        if (valueEnd == -1) {
            valueEnd = url.length();
        }

        return url.substring(valueStart, valueEnd);
    }

    /**
     * 检查字符串是否包含中文
     */
    private static boolean containsChinese(String text) {
        return text.matches(".*[\u4e00-\u9fa5].*");
    }

    /**
     * 搜索策略内部类
     */
    @Getter
    private static class SearchStrategy {
        private final String name;
        private final String query;
        private final int offsetRange;
        private final int maxPages;
        private final int delay;

        public SearchStrategy(String name, String query, int offsetRange, int maxPages, int delay) {
            this.name = name;
            this.query = query;
            this.offsetRange = offsetRange;
            this.maxPages = maxPages;
            this.delay = delay;
        }

    }

    private static String translateToEnglishKeywords(String chineseText) {
        // 简单的中英文映射，实际项目中可以集成翻译API
        Map<String, String> commonTranslations = new HashMap<>();
        commonTranslations.put("风景", "landscape");
        commonTranslations.put("动物", "animal");
        commonTranslations.put("建筑", "architecture");
        commonTranslations.put("花朵", "flower");
        commonTranslations.put("天空", "sky");
        commonTranslations.put("科技", "technology");

        return commonTranslations.getOrDefault(chineseText, chineseText + " photo");
    }

    private static String extractDomain(String url) {
        try {
            int start = url.indexOf("://") + 3;
            int end = url.indexOf("/", start);
            if (end == -1) {
                end = url.length();
            }
            return url.substring(start, end);
        } catch (Exception e) {
            return "unknown";
        }
    }

    private static boolean isReasonableSize(String url) {
        try {
            String widthStr = extractUrlParameter(url, "w");
            String heightStr = extractUrlParameter(url, "h");
            if (widthStr != null && heightStr != null) {
                int width = Integer.parseInt(widthStr);
                int height = Integer.parseInt(heightStr);

                // 最小尺寸要求
                if (width < 300 || height < 300) {
                    return false;
                }

                // 最大尺寸限制（避免过大文件）
                if (width > 4096 || height > 4096) {
                    return false;
                }

                // 宽高比合理性
                double ratio = Math.max(width, height) / (double) Math.min(width, height);
                return ratio <= 4.0;
            }
        } catch (Exception ignored) {
        }

        return true;
    }

    private static String getRatioCategory(double ratio) {
        if (ratio < 0.8) {
            return "portrait";
        } else if (ratio > 1.5) {
            return "landscape";
        } else {
            return "square";
        }
    }

    private static String extractFileIdentifier(String url) {
        // 尝试从URL中提取唯一文件标识符
        if (url.contains("/id/")) {
            try {
                int start = url.indexOf("/id/") + 4;
                int end = url.indexOf("?", start);
                if (end == -1) {
                    end = url.indexOf(".", start);
                }
                if (end == -1) {
                    end = start + 20;
                }
                return url.substring(start, Math.min(end, start + 20));
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    /**
     * 智能延迟管理器
     * 根据抓取效果动态调整延迟策略
     */
    private static class SmartDelayManager {
        private final boolean isFallbackMode;
        private int consecutiveEmptyResponses = 0;
        private long lastRequestTime = 0;
        private final long minInterval = 50; // 最小间隔50ms

        public SmartDelayManager() {
            this(false);
        }

        public SmartDelayManager(boolean isFallbackMode) {
            this.isFallbackMode = isFallbackMode;
        }

        /**
         * 智能延迟：根据抓取成功率动态调整
         */
        public void smartDelay(int successCount, int totalCount) {
            try {
                long currentTime = System.currentTimeMillis();
                long elapsed = currentTime - lastRequestTime;

                if (successCount == 0) {
                    consecutiveEmptyResponses++;
                } else {
                    consecutiveEmptyResponses = 0;
                }

                // 计算需要的延迟时间
                long delayTime = calculateDelayTime(successCount, totalCount, elapsed);

                if (delayTime > 0) {
                    Thread.sleep(delayTime);
                }

                lastRequestTime = System.currentTimeMillis();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        /**
         * 批量延迟：批量处理后的统一延迟
         */
        public void batchDelay() {
            try {
                long delayTime = isFallbackMode ? 200 : 400;
                Thread.sleep(delayTime);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        /**
         * 自适应延迟：根据成功次数调整
         */
        public void adaptiveDelay(int successCount) {
            try {
                // 成功率越高，延迟越短
                long delayTime = Math.max(100, 500 - successCount * 50);
                if (isFallbackMode) {
                    delayTime /= 2; // 兜底模式延迟减半
                }
                Thread.sleep(delayTime);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        /**
         * 计算延迟时间
         */
        private long calculateDelayTime(int successCount, int totalCount, long elapsedTime) {
            // 如果已经过了足够时间，不需要额外延迟
            if (elapsedTime >= minInterval) {
                return 0;
            }

            // 基础延迟
            long baseDelay = isFallbackMode ? 100 : 200;

            // 根据成功率调整
            if (totalCount > 0) {
                double successRate = (double) successCount / totalCount;
                if (successRate > 0.8) {
                    baseDelay = (long) (baseDelay * 0.5); // 成功率高，减少延迟
                } else if (successRate < 0.2) {
                    baseDelay = (long) (baseDelay * 1.5); // 成功率低，增加延迟
                }
            }

            // 连续空响应处罚
            if (consecutiveEmptyResponses > 3) {
                baseDelay += consecutiveEmptyResponses * 100L;
            }

            // 确保不超过最大延迟
            long maxDelay = isFallbackMode ? 500 : 1000;
            baseDelay = Math.min(baseDelay, maxDelay);

            // 减去已经经过的时间
            return Math.max(0, baseDelay - elapsedTime);
        }
    }
}
